/**
 * @file    main.c 
 * @author  18408107475@163.com
 * @version V1.0.0
 * @date    2025-07-19
 * @brief   FreeRTOS多任务示例（LED闪烁+按键控制蜂鸣器）
 * @details 
 * 硬件配置：
 *   - 主控芯片：STM32F10x系列（如STM32F103C8T6）
 *   - 外设：
 *     - 绿色LED（PE5）：系统运行状态指示
 *     - 红色LED（PB5）：错误状态指示
 *     - 蜂鸣器：通过GPIO控制（具体引脚由BEEP_STD_Config.h定义）
 *     - 按键KEY1（PE3）：控制蜂鸣器开关（上拉输入，按下为低电平）
 *   - 连接说明：
 *     - LED采用共阳接法（阳极接3.3V，阴极接GPIO，低电平点亮）
 *     - 按键采用上拉输入（默认高电平，按下接地为低电平）
 * 
 * 软件特性：
 *   - 基于FreeRTOS实现多任务并发：
 *     - LED任务：周期性闪烁绿色LED，优先级较高
 *     - 蜂鸣器任务：轮询按键状态，控制蜂鸣器开关，优先级较低
 *   - 任务间无共享资源冲突（独立控制不同外设）
 *   - 硬件初始化在各自任务中完成，保证任务独立性
 */

/* Includes ------------------------------------------------------------------*/
/* Standard includes. */
#include <stdio.h>              // 标准输入输出库（预留，未实际使用）

/* Scheduler includes. */
#include "FreeRTOS.h"           // FreeRTOS核心头文件（任务、调度器定义）
#include "task.h"               // FreeRTOS任务管理函数（创建、延时等）
#include "queue.h"              // FreeRTOS队列头文件（预留，未实际使用）

/* project app includes. */
#include "LED_STD_Config.h"     // LED控制函数（初始化、亮灭控制）
#include "BEEP_STD_Config.h"    // 蜂鸣器控制函数（初始化、开关控制）

/* Library includes. */
#include "stm32f10x.h"          // STM32F10x外设库（GPIO、RCC等寄存器定义）

/* Task priorities. */
#define mainLED_TASK_PRIORITY   	(tskIDLE_PRIORITY + 2)  // LED任务优先级（较高）
#define mainBEEP_TASK_PRIORITY  	(tskIDLE_PRIORITY + 1)  // 蜂鸣器任务优先级（较低）

/* 按键1硬件配置参数 */
#define KEY1_CLK					RCC_APB2Periph_GPIOE  // KEY1所在GPIO组时钟
#define KEY1_PORT					GPIOE                 // KEY1所在GPIO组
#define KEY1_PIN					GPIO_Pin_3            // KEY1引脚号

/*
 * Configure the KEY1 as required by the project.
 */
static void prvKey1_Config(void);  // KEY1初始化函数（静态，仅本文件可见）

/**
 * @brief  LED闪烁任务函数
 * @param  pvParameters：任务参数（未使用，传入NULL）
 * @note   功能：
 *         1. 初始化LED硬件（PE5、PB5）
 *         2. 周期性控制绿色LED亮300ms、灭700ms（1秒周期）
 *         3. 任务运行期间通过vTaskDelay()释放CPU，进入阻塞态
 */
void vLed_Task(void *pvParameters)
{
	// 初始化LED硬件：配置PB5、PE5为推挽输出，初始为高电平（LED熄灭）
	LED_STD_Config();
	
	// 任务主循环（无限循环，确保任务持续运行）
	for(;;){
		Green_Led_ON();               // 绿色LED点亮（PE5输出低电平）
		vTaskDelay(pdMS_TO_TICKS(300));// 延时300ms（任务阻塞，释放CPU）
		Green_Led_OFF();              // 绿色LED熄灭（PE5输出高电平）
		vTaskDelay(pdMS_TO_TICKS(700));// 延时700ms（任务阻塞，释放CPU）
	}
}

/**
 * @brief  蜂鸣器控制任务函数
 * @param  pvParameters：任务参数（未使用，传入NULL）
 * @note   功能：
 *         1. 初始化蜂鸣器和KEY1按键硬件
 *         2. 轮询KEY1状态：按下时开启蜂鸣器，释放时关闭
 *         3. 每10ms轮询一次，避免过度占用CPU
 */
void vBeep_Task(void *pvParameters)
{
	BEEP_STD_Config();  // 初始化蜂鸣器硬件（配置对应GPIO为推挽输出）
	prvKey1_Config();   // 初始化KEY1为上拉输入

	for(;;){
		// 检测KEY1是否按下（输入低电平）
		if(!GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN)){
			Beep_ON();  // 开启蜂鸣器
			
			// 等待按键释放（循环检测，每10ms延时一次）
			while(!GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN)){
				vTaskDelay(10);  // 短暂延时，降低CPU占用
			}
			
			Beep_OFF();  // 关闭蜂鸣器
		}
		vTaskDelay(10);  // 轮询间隔10ms，平衡响应速度与CPU负载
	}
}

/**
 * @brief  主程序入口
 * @param  None
 * @retval int 程序状态码（实际不会返回，因调度器启动后接管系统）
 * @执行流程：
 *   1. 创建LED任务和蜂鸣器任务
 *   2. 检查任务创建结果，失败则通过红色LED报警
 *   3. 启动FreeRTOS调度器，开始任务调度
 */
int main(void)
{
	BaseType_t 		xReturned;        // 任务创建返回值（pdPASS表示成功）
	TaskHandle_t	LedTaskHandle = NULL;  // LED任务句柄（预留，未实际使用）

	// 创建LED闪烁任务
	xReturned = xTaskCreate(
		vLed_Task,                // 任务函数
		"LED",                    // 任务名称（调试用）
		configMINIMAL_STACK_SIZE, // 任务栈大小（最小配置）
		NULL,                     // 任务参数
		mainLED_TASK_PRIORITY,    // 任务优先级
		&LedTaskHandle            // 任务句柄输出
	);
	
	// 创建蜂鸣器控制任务（不保存任务句柄）
	xTaskCreate(
		vBeep_Task, 
		"Key control Beep", 
		configMINIMAL_STACK_SIZE, 
		NULL, 
		mainBEEP_TASK_PRIORITY, 
		NULL
	);

	// 检查LED任务创建结果（失败处理）
	if(xReturned != pdPASS){
		// 任务创建失败：红色LED常亮
		for(;;){
			Red_Led_ON();               // 点亮红色LED（PB5输出低电平）
			vTaskDelay(pdMS_TO_TICKS(100));// 延时（调度器未启动时无效，实际常亮）
		}
	}

	// 启动FreeRTOS任务调度器（从此处开始，系统由调度器管理）
	vTaskStartScheduler();

    // 调度器启动后不会执行到此处
    while (1)                  
    {
        
    }
}

/**
 * @brief  配置KEY1为上拉输入模式
 * @note   硬件逻辑：
 *         - KEY1按下时接地（输入低电平）
 *         - 未按下时，内部上拉电阻使输入为高电平
 *         - 无需外部上拉电阻，简化硬件设计
 */
static void prvKey1_Config(void)
{
	// 使能KEY1所在GPIO组时钟
	RCC_APB2PeriphClockCmd(KEY1_CLK, ENABLE);

	// 初始化GPIO参数结构体
	GPIO_InitTypeDef GPIO_InitStructure = {
		.GPIO_Mode 	= GPIO_Mode_IPU,      // 上拉输入模式
		.GPIO_Pin 	= KEY1_PIN,           // 对应引脚
		.GPIO_Speed = GPIO_Speed_50MHz,   // 输入模式下速度参数无效
	};

	// 应用配置到指定GPIO组
	GPIO_Init(KEY1_PORT, &GPIO_InitStructure);
}


/************************ (C) COPYRIGHT  END OF FILE************************/
